package core;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class ProductContainerTests
{
	private RootStorageUnit root;
	private Amount amount;
	private Amount amount2;
	private StorageUnit unit1;
	private StorageUnit unit2;
	private ProductGroup group1;
	private ProductGroup group2;
	
	@BeforeClass
	public static void setUpBeforeClass() throws Exception
	{
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception
	{
	}

	@Before
	public void setUp() throws Exception
	{
		root = RootStorageUnit.getInstance();
		amount = new Amount(Unit.count, 0);
		unit1 = new StorageUnit("storage");
		unit2 = new StorageUnit("storage2");
		group1 = new ProductGroup("group1",amount, unit1);
		amount2 = new Amount(Unit.gallons, 5);
		group2 = new ProductGroup("group2",amount2, unit2);
	}

	@Test
	public void getProductGroupsTest()
	{
		StorageUnit newUnit = new StorageUnit("storage1");
		ProductGroup newGroup = new ProductGroup("group1",amount, newUnit);
		ProductGroup newGroup2 = new ProductGroup("group2",amount, newUnit);
		ProductGroup newGroup3 = new ProductGroup("group3",amount, newUnit);
		ProductGroup subGroup = new ProductGroup("sub1", amount2, newGroup3);
		
		newUnit.addProductGroup(newGroup);
		newUnit.addProductGroup(newGroup2);
		newUnit.addProductGroup(newGroup3);
		newGroup3.addProductGroup(subGroup);
		
		assertTrue(newUnit.getProductGroups().size() == 3);
		assertTrue(newGroup3.getProductGroups().size() == 1);
		assertTrue(newUnit.getProductGroups().get(0).getName().compareTo("group1")==0);
	}

	@Test
	public void setNameTest()
	{
		group2.setName("test1");
		assertTrue(group2.getName().compareTo("test1")==0);
		unit2.setName("newUnit");
		assertTrue(unit2.getName().compareTo("newUnit")==0);
	}
	
	@Test
	public void getNameTest()
	{
		group2.setName("newName");
		assertTrue(group2.getName().compareTo("newName")==0);
		unit2.setName("newUnit");
		assertTrue(unit2.getName().compareTo("newUnit")==0);
	}
	
	@Test
	public void addProductGroupTest()
	{
		// this is a duplicate, shouldn't be able to add
		boolean failed = false;
		unit1 = new StorageUnit("newUnit");
		ProductGroup newGroup = new ProductGroup("group1",amount, unit1);
		try	{
			group1.addProductGroup(newGroup);
			assertTrue(group1.containsProductGroup(newGroup));
			group1.addProductGroup(null);
		}
		catch(IllegalArgumentException e)
		{
			failed = true;
		}
		assertTrue(failed);
		
	}
	
	@Test
	public void canAddProductGroupTest()
	{
		StorageUnit newUnit = new StorageUnit("newUnit");
		ProductGroup newGroup = new ProductGroup("group1",amount, newUnit);
		ProductGroup newGroup2 = new ProductGroup("subGroup", amount2, newGroup);
		// this tests the unique constraint of ProductGroup names at 
		// the same level and non-null constraint
		
		assertTrue(newGroup.canAddProductGroup(newGroup2));
		newGroup.addProductGroup(newGroup2);
		assertFalse(newGroup.canAddProductGroup(newGroup2));
		assertFalse(newGroup.canAddProductGroup(newGroup));
		
	}
	@Test
	public void containsProductGroupTest()
	{
		ProductGroup newGroup = new ProductGroup("group1",amount, unit1);
		StorageUnit unit = new StorageUnit("storage1");
		
		ProductGroup newGroup2 = new ProductGroup("group2",amount, unit1);
		newGroup.setParentContainer(newGroup2);
		newGroup2.addProductGroup(newGroup);
		
		assertFalse(group1.containsProductGroup(newGroup));
		assertTrue(newGroup2.containsProductGroup(newGroup));
		
		assertFalse(unit1.containsProductGroup(newGroup));
		newGroup.setParentContainer(unit1);
		unit1.addProductGroup(newGroup);
		assertTrue(unit1.containsProductGroup(newGroup));
	}
	
	@Test
	public void equalsTest()
	{
		
		StorageUnit newUnit = new StorageUnit("storage1");

		ProductGroup newGroup2 = new ProductGroup("group2",amount, unit1);
		ProductGroup newGroup = new ProductGroup("group1",amount, newGroup2);
		ProductGroup newGroup3 = new ProductGroup("group3",amount, newUnit);
		newGroup2.addProductGroup(newGroup);
		
		ProductGroup copy = newGroup;
		
		assertFalse(newGroup2.equals(newGroup));
		assertTrue(newGroup.equals(copy));
		
		assertFalse(newGroup3.equals(newGroup));
		
		
		
	}
	
	@Test
	public void canDeleteProductGroupTest()
	{
		/* This does not test if the ProductGroup to be removed is actually empty,
		 * it only performs the action if possible
		 */
		StorageUnit newUnit = new StorageUnit("storage1");
		ProductGroup newGroup = new ProductGroup("group1",amount, newUnit);
		ProductGroup newGroup2 = new ProductGroup("group2",amount, newGroup);
		newGroup.addProductGroup(newGroup2);
		
		assertTrue(newGroup.canDeleteProductGroup(newGroup2));
		assertFalse(newGroup2.canDeleteProductGroup(newGroup));
		
		boolean nullTest = false;
		try{
			assertFalse(newUnit.canAddProductGroup(null));
		}
		catch(NullPointerException e)
		{
			nullTest = true;
		}
		assertTrue(nullTest);
		
		assertFalse(newUnit.canDeleteProductGroup(newGroup2));
		
		
	}
	
	@Test
	public void deleteProductGroupTest()
	{
		
		StorageUnit newUnit = new StorageUnit("storage1");
		ProductGroup newGroup = new ProductGroup("group1",amount, newUnit);
		ProductGroup newGroup2 = new ProductGroup("group2",amount, newGroup);
		newGroup.addProductGroup(newGroup2);
		
		assertTrue(newGroup.canDeleteProductGroup(newGroup2));
		assertFalse(newGroup.canAddProductGroup(newGroup2));
		assertTrue(newGroup.deleteProductGroup(newGroup2));
		assertTrue(newGroup.canAddProductGroup(newGroup2));
		
	
	}
	
	
	

}
